/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.tree;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.ListPagingRequestMessage;
import cn.easyplatform.messages.request.ListReloadRequestMessage;
import cn.easyplatform.messages.response.ListPagingResponseMessage;
import cn.easyplatform.messages.response.ListQueryResponseMessage;
import cn.easyplatform.messages.vos.datalist.ListPagingVo;
import cn.easyplatform.messages.vos.datalist.ListQueryResultVo;
import cn.easyplatform.messages.vos.datalist.ListRecurVo;
import cn.easyplatform.messages.vos.datalist.ListReloadVo;
import cn.easyplatform.spi.service.ListService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.ext.zul.Actionbox;
import cn.easyplatform.web.ext.zul.Datalist;
import cn.easyplatform.web.ext.zul.Loader;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.zkex.list.SelectableListSupport;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zul.*;
import org.zkoss.zul.event.PagingEvent;
import org.zkoss.zul.event.ZulEvents;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 所有扩展这个类的对象事件自行处理,不需要注册到公共事件管理器中
 *
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public abstract class AbstractSelectableTreeBuilder<T extends Component>
        extends AbstractTreeBuilder implements SelectableListSupport<T> {

    protected T ref;

    AbstractSelectableTreeBuilder(OperableHandler mainTaskHandler,
                                  Datalist listExt, T ref, Component anchor) {
        super(mainTaskHandler, listExt, anchor);
        this.ref = ref;
    }

    protected Component buildToolbar() {
        South south = new South();
        south.setHflex("1");
        south.setBorder("none");

        Component parent = null;
        if (getEntity().getPageSize() > 0) {
            if (getEntity().isFetchAll()) {
                listExt.setMold("paging");
                paging = listExt.getPagingChild();
                parent = south;
            } else {
                Vlayout vlayout = new Vlayout();
                vlayout.setVflex("1");
                vlayout.setHflex("1");
                paging = new Paging();
                paging.setHflex("1");
                paging.addEventListener(ZulEvents.ON_PAGING, this);
                if (layout.getData() == null || layout.getData().isEmpty())
                    paging.setTotalSize(layout.getTotalSize());
                else
                    paging.setTotalSize(layout.getTotalSize());
                paging.setPageSize(getEntity().getPageSize());
                paging.setDetailed(getEntity().isPagingDetailed());
                paging.setHflex("1");
                //paging.setAutohide(getEntity().isPagingAutohide());
                if (layout instanceof ListRecurVo) {
                    int activePage = ((ListRecurVo) layout).getStartPageNo();
                    if (activePage > 0)
                        paging.setActivePage(activePage - 1);
                }
                vlayout.appendChild(paging);
                south.appendChild(vlayout);
                parent = vlayout;
            }
        } else {
            parent = south;
        }
        Hlayout hlayout = new Hlayout();
        hlayout.setHflex("1");
        hlayout.setSclass("text-center");
        Button close = new Button(Labels.getLabel("button.cancel"));
        close.setIconSclass("z-icon-times");
        close.addForward(Events.ON_CLICK, "window", Events.ON_CLOSE);
        close.setParent(hlayout);

        Button confirm = new Button(Labels.getLabel("button.ok"));
        confirm.setIconSclass("z-icon-check");
        confirm.setEvent("select()");
        confirm.addEventListener(Events.ON_CLICK, this);
        confirm.setParent(hlayout);
        parent.appendChild(hlayout);

        return south;
    }

    @Override
    protected Component createContent() {
        Borderlayout layout = new Borderlayout();
        if (getEntity().isShowPanel() && !Strings.isBlank(this.layout.getPanel())) {
            North north = new North();
            north.setHflex("1");
            north.setVflex("1");
            north.setBorder("none");
            north.appendChild(buildPanel(this.layout.getPanel(), null));
            north.setParent(layout);
        }
        layout.appendChild(buildToolbar());
        Center center = new Center();
        center.setHflex("1");
        center.setVflex("1");
        center.setBorder("none");
        layout.appendChild(center);
        layout.setVflex("1");
        layout.setHflex("1");
        listExt.setParent(center);
        if (listExt.isCheckmark() && listExt.isMultiple())
            listExt.addEventListener(Events.ON_SELECT, this);
        return layout;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onEvent(Event event) throws Exception {
        try {
            if (event.getName().equals(Events.ON_CLOSE)) {
                close();
            } else if (event.getName().equals(ZulEvents.ON_PAGING)) {
                PagingEvent evt = (PagingEvent) event;
                paging(evt.getActivePage() + 1);
            } else if (Lang.equals(event.getTarget().getEvent(), "query()")) {
                query(null);
            } else if (event.getName().equals(Events.ON_SELECT)) {
                onSelect((SelectEvent<Component, Set<Component>>) event);
            } else if ("select()".equals(event.getTarget().getEvent())) {
                select(event);
            } else
                super.onEvent(event);
        } catch (EasyPlatformWithLabelKeyException ex) {
            MessageBox.showMessage(ex);
        } catch (BackendException ex) {
            MessageBox.showMessage(ex.getMsg().getCode(), (String) ex.getMsg()
                    .getBody());
        }
    }

    @Override
    public void reload(String... comps) {
        // 重新加载列表数据
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        IResponseMessage<?> resp = dls.doReload(new ListReloadRequestMessage(
                getId(), new ListReloadVo(listExt.getId(), null, false)));
        if (resp.isSuccess()) {
            if (useHeaderVariable)
                createHeader();
            ListQueryResultVo rv = ((ListQueryResponseMessage) resp).getBody();
            if (rv.getData() == null || rv.getData().isEmpty())
                setPagingInfo(0, 0);
            else
                setPagingInfo(rv.getTotalSize(), 0);
            clear();
            listIndex = 0;
            if (rv.getErrMsg() != null)
                setEmptyMessage(rv.getErrMsg());
            else
                redraw(rv.getData());
        } else
            throw new BackendException(resp);
    }

    @Override
    public void paging(int pageNo) {
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        ListPagingRequestMessage req = new ListPagingRequestMessage(
                mainTaskHandler.getId(), new ListPagingVo(listExt.getId(),
                pageNo));
        IResponseMessage<?> resp = dls.doPaging(req);
        if (!resp.isSuccess()) {
            MessageBox.showMessage(resp.getCode(), (String) resp.getBody());
        } else {
            List<ListRowVo> data = ((ListPagingResponseMessage) resp).getBody();
            clear();
            redraw(data);
        }
    }

    @Override
    public void setPageSize(int pageSize) {
        getEntity().setPageSize(pageSize);
        paging.setPageSize(pageSize);
        paging.setActivePage(0);
    }

    @Override
    protected void setPagingInfo(int totalSize, int activePageNo) {
        if (paging != null) {
            if (totalSize >= 0)
                paging.setTotalSize(totalSize);
            paging.setActivePage(activePageNo);
        }
    }

    @Override
    protected void addEventListener(Component comp, String evtnm) {
        if (evtnm == null)
            comp.addEventListener(Events.ON_CLICK, this);
        else
            comp.addEventListener(evtnm, this);
    }

    @Override
    public String getId() {
        return mainTaskHandler.getId();
    }

    protected abstract void close();

    protected void onSelect(SelectEvent<Component, Set<Component>> evt) {
        Treeitem self = (Treeitem) evt.getReference();
        if (self != null) {
            if (getEntity().isCheckall()
                    && self.isContainer()) {
                int checkDepth = 0;
                if (ref instanceof Actionbox)
                    checkDepth = ((Actionbox) ref).getCheckDepth();
                else if (ref instanceof Loader)
                    checkDepth = ((Loader) ref).getCheckDepth();
                int level = self.getLevel();
                if (checkDepth > 0)
                    level += checkDepth;
                else level = 100;
                Iterator<Component> itr = self
                        .queryAll("treeitem").iterator();
                while (itr.hasNext()) {
                    Treeitem ti = (Treeitem) itr.next();
                    if (self.isSelected()) {
                        if (level >= ti.getLevel()) {
                            ti.setSelected(true);
                            evt.getSelectedItems().add(ti);
                        } else {
                            ti.setSelected(false);
                            evt.getUnselectedItems().add(ti);
                        }
                    } else {
                        ti.setSelected(false);
                        evt.getUnselectedItems().add(ti);
                    }
                }
            }
        }
    }
}
